package org.ddevil.data;

import java.util.ArrayList;
import java.util.Iterator;

import org.ddevil.data.util.DataSetUtils;
import org.ddevil.data.util.DataUtils;


/***
 * This class acts as the base attributes object. The keys in this class are not
 * case sensitive. This class is synchronized on write so it should be thread
 * safe.
 *
 * @author Eric Lundin
 * @author Rich
 * TODO RENAME
 */
public class BasicData implements Data {

	private static final long serialVersionUID = 8846473480257134434L;

	/***
	 * The error message to display whenthe given arrays of identifiers and
	 * values do not match in size.
	 */
	private static final String ERR_ARRAY_SIZE_MISMATCH = "ID array length must match value array length.";

	/***
	 * The attributes this criteria object holds.
	 */
	private CaseInsensitiveHashtable<Attribute> attributes;

	/***
	 * Create a new empty BasicData object.
	 */
	public BasicData() {
		this(10);
	}

    /***
     * Create a new empty BasicData object with the given initial capacity.
     * @param initialCapacity
     */
    public BasicData(int initialCapacity){
        attributes = new CaseInsensitiveHashtable<Attribute>((int)(initialCapacity/.75), .75f);
    }

	/***
	 * Create a new BasicData Object using the given arrays as the initial
	 * data. Each db id in the given dbIds array will be mapped to the value in
	 * the given values array.
	 *
	 * @param dbIds
	 *            The identifiers to use.
	 * @param values
	 *            The values to map to the given identifiers.
	 * @throws IllegalArgumentException
	 *             If the two arrays are not the same size.
	 */
	public BasicData(String[] dbIds, Object[] values) {
		this(dbIds.length);
		addItems(dbIds, values);
	}

	/***
	 * Create a new BasicData object using the given list of DataItems as
	 * the initial data.
	 *
	 * @param data
	 *            The set of data items this attributes object will hold.
	 */
	public BasicData(ArrayList<Attribute> data) {
		this(data.size());
		for (Attribute current : data) {
			addDataItem(current);
		}
	}

    /***
     * Create a new BasicData object containing each Attribute contained
     * in the Data parameter
     * @param data
     */
    public BasicData(Data data){
        this(data.size());
        for (Attribute current : data) {
            addDataItem(current);
        }

    }

	/**
	 * {@inheritDoc}
	 */
	public boolean contains(String dbIdentifier) {
		return attributes.containsKey(dbIdentifier);
	}

	/**
	 * {@inheritDoc}
	 */
	public int size() {
		return attributes.size();
	}

	/**
	 * {@inheritDoc}
	 */
	public Iterator<Attribute> iterator() {
		return attributes.values().iterator();
	}

	/**

	 *
	 * {@inheritDoc}
	 */
	public Attribute getDataItem(String dbIdentifier) {
		return attributes.get(dbIdentifier);
	}

	/**
	 * {@inheritDoc}
	 */
	public Object getValue(String dbIdentifier) {
		Object rv = null;
		Attribute val = attributes.get(dbIdentifier);
		if (val != null) {
			rv = val.getValue();
		}
		return rv;
	}

	/**

	 *
	 * {@inheritDoc}
	 */
	public synchronized void addDataItem(Attribute item) {
		if (item != null) {
			attributes.put(item.getId(), item);
		}
	}

	/***
	 * Add the each Attribute in the list to this attributes object.
	 *
	 * @param items
	 *            The items to add.
	 */
	public synchronized void addDataItems(ArrayList<Attribute> items) {
		for (Attribute current : items) {
			addDataItem(current);
		}
	}

	/***
	 * Convenience method for adding multiple items. Each id in the dbIds array
	 * will be mapped to the corresponding value in the values array.
	 *
	 * @param dbIds
	 *            The identifiers of the attributes.
	 * @param values
	 *            The values to map to these attributes.
	 * @throws IllegalArgumentException
	 *             If the length of the arrays are not equal.
	 */
	public synchronized void addItems(String[] dbIds, Object[] values) {
		if (dbIds != null && values != null) {
			// XXX commenting 8/26/08 see above
//			if (dbIds.length != values.length) {
//				throw new IllegalArgumentException(ERR_ARRAY_SIZE_MISMATCH);
//			}

			for (int i = 0; i < dbIds.length; i++) {
				addDataItem(new Attribute(dbIds[i], values[i]));
			}

		}
	}

	/***
	 * Add an attribute and its corresponding data mapping to the set of
	 * attributes.
	 *
	 * @param dbId
	 *            The identifier for this attribute.
	 * @param value
	 *            The value to map to the given identifier.
	 */
	public synchronized void addItem(String dbId, Object value) {
		addDataItem(new Attribute(dbId, value));
	}


    /**
     * {@inheritDoc}
     */
    public synchronized void setDataItem(String dbId, Object newValue) {
        addItem(dbId, newValue);
    }

	/**
	 * {@inheritDoc}
	 */
	public synchronized void removeDataItem(String dbId) {
		attributes.remove(dbId);
	}

	/**
	 * {@inheritDoc}
	 */
	public synchronized void copyDataFrom(Data in) {
		for (Attribute a : in) {
			setDataItem(a.getId(), a.getValue());
		}
	}

	@Override
	public String toString() {
		return DataUtils.formatDoubleArrayForPrint(DataSetUtils
				.attributesToArray(this));
	}
}
